<html>
    <head>
        <title>Voice on Web</title>
        <meta content="text/html; application/json; charset=utf-8" http-equiv="Content-Type" />

        <style>
            html,body {
                font:normal 0.9em arial,helvetica;
            }
            #msg {
                width:330px;
            }
            .signup {
                border: 1px solid #999999;
                font: normal 14px helvetica;
                color:#444444;
            }
        </style>
        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script>
        <script type="text/javascript" src="validate_functions.js"></script>
        <script type="text/javascript" src="json.js"></script>
        <script type="text/javascript" src="json2.js"></script>
        <script type="text/javascript" src="json_parse.js"></script>
        <script type="text/javascript" src="json_parse_state.js"></script>
        <script type="text/javascript">

            // the web socket to the server
            var socket;

            // this sequence number is used to generate the next message id.
            var count = 1;

            // pending REST request to the server, which are pending a response.
            // In this table: Key is the msg_id and value is the response callback function.
            var pending_request = {};

            // the timeout in seconds, for retrying connection, with exponential back-off and limit of 1 minute
            var timeout = 125;

            // the current target email with whom we are chatting with, if any?
            var target = null;

            // the call state is "inviting", "received", "active" or "null"
            var call_state = null;

            // local voice stream name
            var stream = null;

            // local voice secure token
            var nearID = null;

            function init() {
                var host = "ws://127.0.0.1:8080/socket/newsocket/server.php";
                try{
                    socket = new WebSocket(host);
                    console.log('websocket.init: status=' + socket.readyState);
                    $('initForm').innerHTML = 'Connecting...';

                    socket.onopen    = function(msg){
                        console.log("websocket.onopen: status=" + this.readyState);
                        timeout = 125;
                        show('loginForm');
                        var email = getQueryVariable('email');
                        var password = getQueryVariable('password');
                        console.log(email + ' ' + password);
                        if (email != null && password != null) {
                            $('login_email').value = email;
                            $('login_password').value = password;
                        }
                    };
                    socket.onmessage = function(msg){
                        console.log("Received: " + msg.data);
                        received(msg.data);
                    };
                    socket.onclose   = function(msg){
                        console.log("websocket.onclose: status=" + this.readyState+ ". reconnecting in " + timeout/1000.0+" seconds");
                        $('initForm').innerHTML = 'Connect failed. reconnecting in ' + timeout / 1000.0 + ' seconds. Refresh this page to connect now.';

                        setTimeout("init()", timeout);
                        if (timeout < 60000) {
                            timeout *= 2;
                        }
                    };
                }
                catch(ex){
                    console.log(ex);
                }

                $("login_email").focus();
            }

            function getQueryVariable(variable) {
                var query = window.location.search.substring(1);
                var vars = query.split("&");
                for (var i=0;i<vars.length;i++) {
                    var pair = vars[i].split("=");
                    if (pair[0] == variable) {
                          return pair[1];
                    }
                }
                return null;
            }

            function validate(command) {
                if (command == "login") {
                    fail = validateEmail($("login_email").value)
                    fail += validatePassword($("login_password").value)
                } else {
                    fail = validateEmail($("signup_email").value)
                    fail += validateFirstname($("signup_firstname").value)
                    fail += validateLastname($("signup_lastname").value)
                    fail += validatePassword($("signup_password").value)
                }
                if (fail == "") {
                    return true
                } else {
                    alert(fail);
                    return false;
                }
            }

            // show one of loginForm, signupForm or activeForm

            function show(formname) {
                $('initForm').style.visibility = formname == 'initForm' ? 'visible' : 'hidden';
                $('loginForm').style.visibility = formname == 'loginForm' ? 'visible' : 'hidden';
                $('signupForm').style.visibility = formname == 'signupForm' ? 'visible' : 'hidden';
                $('activeForm').style.visibility = formname == 'activeForm' ? 'visible' : 'hidden';

                if (formname == 'activeForm') {
                    start_local_audio();
                }
            }

            function received(response) {
                console.log(response);
                if (response.charAt(0) == '\u0000'){
                    response = response.substring(1);
                }
                response = JSON.parse(response);

                if (response.msg_id && pending_request[response.msg_id]) {
                    pending_request[response.msg_id](response);
                    delete pending_request[response.msg_id];
                } else if (response.method == 'NOTIFY') {
                    received_notify(response);
                }
            }

            function send(request, response_callback) {
                request.msg_id = count++;
                pending_request[request.msg_id] = response_callback;

                try {
                    var value = JSON.stringify(request);
                    console.log('Sending: ' + value);
                    socket.send(value);
                } catch (ex) {
                    console.log(ex);
                }

                //setTimeout('var response = {"msg_id": ' + request.msg_id + ', "code": "success"}; received(response);', 3000);
            }

            function login() {
                var request = {"method": "POST", "resource": "/contact",
                    "email" : $("login_email").value,  "password" : $("login_password").value};

                send(request, function(response) {
                    if (response.code == "success") {
                        show('activeForm')
                        whoisonline();
                    } else {
                        alert(response.code + ":" + response.reason);
                    }
                });
            }

            function logout() {
                var request = {"method": "DELETE", "resource": "/contact"};
                send(request, function(response) {
                    if (response.code == "success") {
                        $("userlistBox").innerHTML = "";
                        $('historyBox').value="";
                        show('loginForm');
                        $("login_email").focus();

                    } else {
                        alert(response.code + ": " + response.reason);
                    }
                });
            }

            function signup() {
                var request = {"method": "POST", "resource": "/user",
                    "email" : $("signup_email").value,  "password" : $("signup_password").value,
                    "firstname" : $("signup_firstname").value, "lastname" : $("signup_lastname").value};

                send(request, function(response) {
                    if (response.code == "success") {
                        show('loginForm');
                        $("login_email").value = $("signup_email").value;
                        $("login_password").value = $("signup_password").value;
                    } else {
                        alert(response.code + ": " + response.reason);
                    }
                });
            }

            function whoisonline(){
                var request = {"method": "GET", "resource": "/contact"};
                send(request, function(response) {
                    if (response.code == "success") {
                        update_members(response.contact);
                    } else {
                        $("userlistBox").innerHTML = "";
                    }
                });
            }

            function update_members(members) {
                var data = "";
                console.log('members=' + members);
                for (var i=0; i<members.length; ++i) {
                    var member = members[i];
                    console.log('member=' + member);
                    data += "<a onclick='invite(\"" + member.email + "\"); return false;' href='#'>"
                            + member.firstname + " " + member.lastname + "</a><br/>";
                }
                console.log('setting userlistBox to ' + data);
                $("userlistBox").innerHTML = data;
            }

            function sendmsg() {
                var msg = $('chatInput').value;
                $('chatInput').value = "";
                $('chatInput').focus();
                console.log('sending msg ' + msg);
                writeHistory($("login_email").value + ": " + msg);
                var request = {"method": "NOTIFY", "resource": "/contact",
                        "email": (target == null ? "*" : target), "text": msg};
                send(request, function(response) {
                    if (response.code == 'failed') {
                        $('historyBox').value += 'failed to send your message: ' + response.reason;
                    }
                });
            }

            function received_notify(request) {
                if (request.text) {
                    writeHistory(request.from_email + ': ' + request.text);
                } else if (request.inviteURL) {
                    received_invite(request);
                } else if (request.acceptURL) {
                    received_accept(request);
                } else if (request.terminate) {
                    received_hangup(request);
                } else if (request.contact) {
                    update_members(request.contact);
                }
            }

            function writeHistory(msg) {
                $('historyBox').value += msg + "\n";
            }

            function set_call_state(state) {
                call_state = state;
                $("hangupButton").style.visibility = call_state != null ? "visible" : "hidden";
            }

            function invite(email) {
                if (call_state == null && nearID != null) {
                    set_call_state("inviting");
                    target = email;
                    writeHistory("Inviting " + email + " to a voice call");
                    $("textChatTitle").innerHTML = "Text chat with " + email;

                    var url = "rtmfp://stratus.rtmfp.net/d1e1e5b3f17e90eb35d244fd-c711881365d9/"
                        + "?play=" + stream + "&farID=" + nearID;
                    var request = {"method": "NOTIFY", "resource": "/contact", "email": target,
                                "inviteURL": url};
                    send(request, function(response) {
                        console.log("inviting response " + response.code);
                        if (response.code == 'failed') {
                            set_call_state(null);
                            writeHistory("Failed to invite: " + response.reason);
                        }
                    });
                } else if (nearID == null) {
                    console.log("nearID is invalid");
                    writeHistory('failed to invite as your voice module was not initialized');
                } else {
                    console.log("not in idle call state: " + call_state);
                    writeHistory('failed to invite as you are already in an active or pending call');
                }
            }

            function received_invite(request) {
                if (call_state != null) {
                    writeHistory('missed call from ' + request.from_email);
                    var response = {"method": "NOTIFY", "resource": "/contact",
                                "terminate": true, "rejectReason": "busy here"}
                    send(response, function(response) { });
                } else {
                    set_call_state('incoming');
                    var answer = confirm("Incoming call from " + request.from_email + ". Accept?");
                    if (answer) {
                        target = request.from_email;
                        writeHistory('accepting call from ' + request.from_email);
                        $("textChatTitle").innerHTML = "Text chat with " + target;
                        set_call_state("active");

                        getFlashMovie("video2").setProperty("src", request.inviteURL);
                        var url = "rtmfp://stratus.rtmfp.net/d1e1e5b3f17e90eb35d244fd-c711881365d9/"
                            + "?play=" + stream + "&farID=" + nearID;
                      /*  var response = {"method": "NOTIFY", "resource": "/contact",
                                "terminate": true, "rejectReason": "busy here"};
                       */
                        var response = {"method": "NOTIFY", "resource": "/contact", "email": target, "acceptURL": url};
                        console.log(response);
                        send(response, function(response) { });
                    } else {
                        set_call_state(null);
                        writeHistory('rejecting call form ' + request.from_email);
                        response = {"method": "NOTIFY", "resource": "/contact",
                                    "terminate": true, "rejectReason": "decline"}
                        send(response, function(response) { });
                    }
                }
            }

            function received_accept(request) {
                if (call_state == 'inviting') {
                    set_call_state("active");
                    writeHistory('call accepted by ' + request.from_email);
                    getFlashMovie("video2").setProperty("src", request.acceptURL);
                }
            }

            function hangup() {
                if (call_state != null) {
                    set_call_state(null);
                    getFlashMovie("video2").setProperty("src", null);

                    writeHistory("call terminating");

                    var request = {"method": "NOTIFY", "resource": "/contact",
                                "email": target, "terminate": true};
                    send(request, function(response) { });
                }
            }

            function received_hangup(request) {
                if (call_state != null) {
                    set_call_state(null);
                    getFlashMovie("video2").setProperty("src", null);

                    writeHistory("call terminated" + (request.rejectReason ? ": " + request.rejectReason : ""));
                }
            }

            // start the local VideoIO and get the secure token (nearID)
            function start_local_audio() {
                stream = "vow" + Math.random();
                var url = "rtmfp://stratus.rtmfp.net/d1e1e5b3f17e90eb35d244fd-c711881365d9/"
                        + "?publish=" + stream;
                getFlashMovie("video1").setProperty("src", url);
            }

            // Utilities
            function $(id){ return document.getElementById(id); }
            function log(msg){ $("log").innerHTML += "\n" + msg; }
            function onkey(event){ if(event.keyCode==13){ sendmsg(); } }
    </script>

    </head>
    <body onload="init();">
        <h3>Voice on Web</h3>

        <div id="initForm" style="position:absolute; left: 20px; top: 50px; visibility: visible;">
            Please wait file it is connecting to the server!
        </div>

        <div id="loginForm" style="position:absolute; left: 20px; top: 50px; visibility: hidden;">
            <table class="signup" border="0" cellpadding="2" cellspacing="5" bgcolor="#eeeeee">
                <th colspan="2" align="center">Login</th>
                <tr>
                    <td>Email</td>
                    <td><input type="text" maxlength="64" id="login_email"/></td>
                </tr>
                <tr>
                    <td>Password</td>
                    <td><input type="password" maxlength="20" id="login_password"/></td>
                </tr>
                <tr>
                    <td align="center"><button onclick="if (validate('login')) { login();}">Login</button></td>
                    <td align="center"><button onclick="show('signupForm')">New user?</button</td>
                </tr>
            </table>
        </div>

        <div id="signupForm" style="position:absolute; left: 20px; top: 50px; visibility: hidden;">
            <table class="signup" border="0" cellpadding="2" cellspacing="5" bgcolor="#eeeeee">
                <th colspan="2" align="center">New User Signup</th>
                <tr>
                    <td>Email</td>
                    <td><input type="text" maxlength="64" id="signup_email"/></td>
                </tr>
                <tr>
                    <td>Password</td>
                    <td><input type="password" maxlength="20" id="signup_password" /></td>
                </tr>
                <tr>
                    <td>Firstname</td>
                    <td><input type="text" maxlength="32" id="signup_firstname" /></td>
                </tr>
                <tr>
                    <td>Lastname</td>
                    <td><input type="text" maxlength="32" id="signup_lastname" /></td>
                </tr>
                <tr>
                    <td align="center"><button onclick="if (validate('signup')) { signup(); }">Sign up</button></td>
                    <td align="center"><button onclick="show('loginForm'); return false;">Cancel</button></td>
                </tr>
            </table>
        </div>

        <div id="activeForm" style="position:absolute; left: 20px; top: 50px; visibility: hidden; background-color: #eeeeee; border: 1px solid #cfcfcf; width: 660px; height: 500px;">
            <div style="position:absolute; left: 5px; top: 5px;">Online users</div>
            <div id="userlistBox" style="position:absolute; left: 5px; top: 30px; width: 190px;height: 400px; background-color: #ffffff; border: 1px solid #cfcfcf; padding: 5px 0px 0px 5px;">
            </div>

            <div id="textChatTitle" style="position:absolute; left: 205px; top: 175px;">
                Text chat
            </div>
            <textarea cols="" rows=""  id="historyBox" readonly="readonly" style="position:absolute; left: 205px; top: 195px; width: 450px; height: 205px;"></textarea>

            <input id="chatInput" type="text" value="Type your message here" onkeypress="onkey(event);"
                    style="position:absolute; left: 205px; top: 405px; width: 450px; height: 30px;"/>


            <div id="voiceCallTitle" style="position:absolute; left: 205px; top: 5px;">
                Voice call
                <button id="hangupButton" style="visibility: hidden;" onclick="hangup()">hang up</button>
            </div>

            <div style="position:absolute; left: 205px; top: 30px; width: 450px; height: 140px; background-color: #ffffff; border: 1px solid #cfcfcf;">
                <script type="text/javascript">
                    var nearID = null;

                    function getFlashMovie(movieName) {
                        var isIE = navigator.appName.indexOf("Microsoft") != -1;
                        return (isIE) ? window[movieName] : document[movieName];
                    }

                    function onCreationComplete(event) {
                    }

                    function onPropertyChange(event) {
                        if (event.property == "nearID") {
                            if (event.objectID == "video1") {
                                nearID = event.newValue;
                            }
                        } else if (event.property == "camera") {
                            if (event.newValue) {
        //                        getFlashMovie("video1").setProperty("camera", false);
                            }
                        }
                    }
                </script>
                <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
                    id="video1" width="215" height="138"
                    codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
                    <param name="movie" value="VideoIO.swf" />
                    <param name="quality" value="high" />
                    <param name="bgcolor" value="#ffffff" />
                    <param name="wmode" value="transparent" />
                    <param name="allowScriptAccess" value="always" />
                    <embed src="VideoIO.swf" quality="high" bgcolor="#ffffff"
                        width="215" height="138" name="video1" align="middle"
                        play="true" loop="false" quality="high" wmode="transparent"
                        allowScriptAccess="always"
                        type="application/x-shockwave-flash"
                        pluginspage="http://www.adobe.com/go/getflashplayer">
                    </embed>
                </object>
                <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
                    id="video2" width="215" height="138"
                    codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
                    <param name="movie" value="VideoIO.swf" />
                    <param name="quality" value="high" />
                    <param name="bgcolor" value="#ffffff" />
                    <param name="wmode" value="transparent" />
                    <param name="allowScriptAccess" value="always" />
                    <embed src="VideoIO.swf" quality="high" bgcolor="#ffffff"
                        width="215" height="138" name="video2" align="middle"
                        play="true" loop="false" quality="high" wmode="transparent"
                        allowScriptAccess="always"
                        type="application/x-shockwave-flash"
                        pluginspage="http://www.adobe.com/go/getflashplayer">
                    </embed>
                </object>
            </div>

            <div id="logOut" style="position:absolute; left: 5px; top: 450px;">
                <button onclick="logout();">Logout</button>
            </div>
        </div>

<!-- use console.log as that is more robust.

        <div style="position:absolute; top:10px; left:700px; border: 1px solid #cfcfcf; width: 400px; height: 600px;">
            <b>Trace</b><br/>
            <textarea id="log" cols="" rows="" style="width: 398px; height: 580px"></textarea>
        </div>
-->

    </body>
</html>
